DF_HEAD = b'\xff'


class DataFrameIn:
    """ Used to parse the data frame received.  """
    def __init__(self, frame_size):
        self._buf = bytearray()
        self.frame_size = frame_size
        self.escape = False
        
    def bs_to_int(self, start, size, signed=False):
        _bs = self._buf[start:start+size]
        # print(_bs)
        # print(self._buf)
        return int.from_bytes(_bs, 'little', signed=signed)
        
    def bs_to_u16(self, start):
        return self.bs_to_int(start, 2, False)
       
    def bs_to_u16d1(self, start):
        return self.bs_to_int(start, 2, False) / 10.0
    
    def bs_to_s16(self, start):
        return self.bs_to_int(start, 2, True)
    
    def bs_to_s16d1(self, start):
        return self.bs_to_int(start, 2, True) / 10.0
    
    def feed(self, bs:bytes):
        """If the whole frame is received, return True, otherwise, return False."""
        print(bs)
        if not self.escape and bs == DF_HEAD:
            self.escape = True
            print(1)
            return False
        elif len(self._buf) < self.frame_size:
            self._buf.extend(bs)
            print(2)

            return False
        elif len(self._buf) == self.frame_size:
            print(3)

            return True
    
    def reset(self):
        """ Reset to init state. """
        self._buf = bytearray()
        self.escape = False


class DataFrameOut:
    """ Used to assemble the data frame to write.  """
    
    def __init__(self, frame_size):
        """:param frame_size: size including DF_HEAD"""
        self.buf = bytearray(frame_size)
    
    def val_to_bs(self, val, start, size, signed=False, digits=0):
        """
        Convert the value of int type or float type into bytes.
        
        :param size: in bytes.
        :param digits: the number of digits of decimal."""
        val = val*pow(10, digits)
        _bs = int(val).to_bytes(size, 'little', signed=signed)
        
        for i, b in enumerate(_bs):
            self.buf[start+i] = b
    
    def u16_to_bs(self, start, val):
        self.val_to_bs(val, start, 2, signed=False, digits=0)
    
    def u16d1_to_bs(self, start, val):
        self.val_to_bs(val, start, 2, signed=False, digits=1)
    
    def s16_to_bs(self, start, val):
        self.val_to_bs(val, start, 2, signed=True, digits=0)
    
    def s16d1_to_bs(self, start, val):
        self.val_to_bs(val, start, 2, signed=True, digits=1)
    
    @property
    def buf_to_send(self):
        """ The buffer that added the DF_HEAD at the beginning of data
        part."""
        return DF_HEAD + self.buf
    
    
if __name__ == '__main__':
    df_out = DataFrameOut(10)
    df_out.u16_to_bs(0, 1)
    df_out.s16_to_bs(2, -1)
    df_out.s16d1_to_bs(4, -5.5)
    
    print(df_out.buf)
    
    df_in = DataFrameIn(10)
    print(df_in.bs_to_u16(0))
    print(df_in.bs_to_s16(2))
    print(df_in.bs_to_s16d1(4))
    
    
    
    
    

